﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using M3G;

namespace MyTestProject {
    public class TestNode {

        [Fact]
        public void TestConstructor () {
            var node = (Node)new Group ();

            Assert.Equal (null, node.Parent);
            Assert.Equal (true, node.RenderingEnabled);
            Assert.Equal (true, node.PickingEnabled);
            Assert.Equal (true, node.CollisionEnabled);
            Assert.Equal (1.0f, node.AlphaFactor);
            Assert.Equal (0xffffffff, node.Scope);
            Assert.Equal (Node.None, node.AlignmentTarget[Node.YAxis]);
            Assert.Equal (Node.None, node.AlignmentTarget[Node.ZAxis]);
            Assert.Equal (null, node.AlignmentReference[Node.YAxis]);
            Assert.Equal (null, node.AlignmentReference[Node.ZAxis]);
            Assert.Equal (0.0f, node.LODResolution);
            Assert.Equal (null, node.BoundingBox);
            Assert.Equal (null, node.BoundingSphere);
            Assert.Equal (0, node.GetCollisionShape (null, null));
        }

        [Fact]
        public void TestSetRenderingEnabled () {
            var node  = new Group ();
            node.RenderingEnabled = false;

            Assert.Equal (false, node.RenderingEnabled);
        }

        [Fact]
        public void TestSetPickingEnabled () {
            var node = new Group ();
            node.PickingEnabled = false;

            Assert.Equal (false, node.PickingEnabled);
        }

        [Fact]
        public void TestSetCollisionEnabled () {
            var node = new Group ();
            node.CollisionEnabled = false;

            Assert.Equal (false, node.CollisionEnabled);
        }

        [Fact]
        public void TestSetScope () {
            var node = new Group ();
            node.Scope = 0x12345678;

            Assert.Equal (0x12345678u, node.Scope);
        }

        [Fact]
        public void TestSetAlphaFactor () {
            var node= new Group ();
            node.AlphaFactor = 0.1f;

            Assert.Equal (0.1f, node.AlphaFactor);
        }

        [Fact]
        public void TestSetBoundingBox () {
            var node = new Group ();
            var bbox = new float[] { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
            node.SetBoundingBox (bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]);

            Assert.Equal (bbox, node.BoundingBox);
        }

        [Fact]
        public void TestSetBoundingSphere () {
            var node = new Group ();
            var bsph = new float[] { 1.0f, 2.0f, 3.0f, 4.0f };
            node.SetBoundingSphere (bsph[0], bsph[1], bsph[2], bsph[3]);

            Assert.Equal (bsph, node.BoundingSphere);
        }

        [Fact]
        public void TestSetAlignmentReference () {
            var node = new Group ();
            var zRef = new Group ();
            var yRef = new Group ();
            node.SetAlignment (zRef, Node.Origin, yRef, Node.Origin);

            Assert.Equal (zRef, node.AlignmentReference[Node.ZAxis]);
            Assert.Equal (yRef, node.AlignmentReference[Node.YAxis]);
            Assert.Equal (Node.Origin, node.AlignmentTarget[Node.ZAxis]);
            Assert.Equal (Node.Origin, node.AlignmentTarget[Node.YAxis]);
        }

        [Fact]
        public void TestSetCollisionShape () {
            var nod = (Node)new Group ();

            var orientations = (1 << 5 | 1 << 4 | 1 << 0);
            var min = new float[] { 1, 2, 3, 4, 5, 6 };
            var max = new float[] { 7, 8, 9, 10, 11, 12 };
            nod.SetCollisionShape (orientations, min, max);

            var expectedMin = new float[] { 1, 0, 0, 0, 5, 6 };
            var expectedMax = new float[] { 7, 0, 0, 0, 11, 12 };
            var outMin = new float[6];
            var outMax = new float[6];

            Assert.Equal (orientations, nod.GetCollisionShape (outMin, outMax));
            Assert.Equal (expectedMin, outMin);
            Assert.Equal (expectedMax, outMax);
        }

        [Fact]
        public void TestDuplicate () {
            var bbox = new float[] { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
            var bsph = new float[] { 1.0f, 2.0f, 3.0f, 4.0f };
            var zRef = new Group ();
            var yRef = new Group ();
            var orientations = (1 << 5 | 1 << 4 | 1 << 0);
            var min = new float[] { 1, 2, 3, 4, 5, 6 };
            var max = new float[] { 7, 8, 9, 10, 11, 12 };
            var nod = new Group ();
            nod.RenderingEnabled = false;
            nod.PickingEnabled = false;
            nod.CollisionEnabled = false;
            nod.Scope = 0x12345678;
            nod.AlphaFactor = 0.1f;
            nod.SetBoundingBox (bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]);
            nod.SetBoundingSphere (bsph[0], bsph[1], bsph[2], bsph[3]);
            nod.SetAlignment (zRef, Node.Origin, yRef, Node.Origin);
            nod.SetCollisionShape (orientations, min, max);
            nod.UserID = 100;

            var dup = (Node)nod.Duplicate ();

            Assert.Equal (nod.Parent, nod.Parent);
            Assert.Equal (nod.RenderingEnabled, nod.RenderingEnabled);
            Assert.Equal (nod.PickingEnabled, nod.PickingEnabled);
            Assert.Equal (nod.CollisionEnabled, nod.CollisionEnabled);
            Assert.Equal (nod.AlphaFactor, nod.AlphaFactor);
            Assert.Equal (nod.Scope, nod.Scope);
            Assert.Equal (nod.AlignmentTarget[Node.YAxis], nod.AlignmentTarget[Node.YAxis]);
            Assert.Equal (nod.AlignmentTarget[Node.ZAxis], nod.AlignmentTarget[Node.ZAxis]);
            Assert.Equal (nod.AlignmentReference[Node.YAxis], nod.AlignmentReference[Node.YAxis]);
            Assert.Equal (nod.AlignmentReference[Node.ZAxis], nod.AlignmentReference[Node.ZAxis]);
            Assert.Equal (nod.LODResolution, nod.LODResolution);
            Assert.Equal (nod.BoundingBox, nod.BoundingBox);
            Assert.Equal (nod.BoundingSphere, nod.BoundingSphere);
            Assert.Equal (nod.GetCollisionShape (null, null), nod.GetCollisionShape (null, null));
            Assert.Equal (nod.UserID, dup.UserID);
        }

        /**
         * バウンディングスフィアによってカリングされることを確認するテスト
         * */
        [Fact]
        public void TestCulledByBoundingVolume1 () {
            var nod = new Group ();
            nod.SetBoundingSphere (1, 1, 1, 1);

            var pos = new float[] { 10, 10, 10 };
            var dir = new float[] { 0, 0, -1 };
            Assert.Equal (true, nod.CulledByBoundingVolume (pos, dir));

        }

        /**
         * バウンディングボックスによってカリングされることを確認するテスト
         * */
        [Fact]
        public void TestCulledByBoundingVolume2 () {
            var nod = new Group ();
            nod.SetBoundingBox (0, 2, 0, 2, 0, 2);

            var pos = new float[] { 10, 10, 10 };
            var dir = new float[] { 0, 0, -1 };
            Assert.Equal (true, nod.CulledByBoundingVolume (pos, dir));
        }

        /**
         * バウンディングボックスとバウンディングスフィアの合わせ技でカリングされることを確認するテスト
         * */
        [Fact]
        public void TestCulledByBoundingVolume3 () {
            var nod = new Group ();
            nod.SetBoundingSphere (1, 1, 1, 10);
            nod.SetBoundingBox (0, 2, 0, 2, 0, 2);

            var pos = new float[] { 5, 5, 10 };
            var dir = new float[] { 0, 0, -1 };
            Assert.Equal (true, nod.CulledByBoundingVolume (pos, dir));
        }



        /**
         * 存在しないバウンディングボリュームによってカリングされないことを確認するテスト
         * */
        [Fact]
        public void TestCulledByBoundingVolume4 () {
            var nod = new Group ();

            var pos = new float[] { 10, 10, 10 };
            var dir = new float[] { 0, 0, -1 };
            Assert.Equal (false, nod.CulledByBoundingVolume (pos, dir));
        }

        /**
         * バウンディングスフィアによってカリングされないことを確認するテスト
         * */
        [Fact]
        public void TestCulledByBoundingVolume5 () {
            var nod = new Group ();
            nod.SetBoundingSphere (1, 1, 1, 1);

            var pos = new float[] { 1, 1, 10 };
            var dir = new float[] { 0, 0, -1 };
            Assert.Equal (false, nod.CulledByBoundingVolume (pos, dir));
        }

        /**
         * バウンディングボックスによってカリングされないことを確認するテスト
         * */
        [Fact]
        public void TestCulledByBoundingVolume6 () {
            var nod = new Group ();
            nod.SetBoundingBox (0, 2, 0, 2, 0, 2);

            var pos = new float[] { 1, 1, 10 };
            var dir = new float[] { 0, 0, -1 };
            Assert.Equal (false, nod.CulledByBoundingVolume (pos, dir));
        }

    }
}
